<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * This file contains the PDODB_Connection_mssql class.
 *
 * PHP version 5
 *
 * This file is part of PEAR::PDODB - A database abstraction layer for PHP5 built
 * using PDO. PHP version 5.1+ is recommended.
 *
 * PEAR::PDODB is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * PEAR::PDODB is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PEAR::PDODB. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package     PDODB
 * @subpackage  mssql
 * @category    Database
 * @author      Frank M. Kromann <frank@kromann.info>
 * @author      Michael J. I. Jackson <mjijackson@gmail.com>
 * @copyright   1998-2007 Manuel Lemos, Tomas V.V. Cox, Stig S. Bakken, Lukas Smith
 * @copyright   2007 Michael J. I. Jackson
 * @license     http://www.gnu.org/licenses/lgpl-3.0.txt GNU LGPL 3.0
 * @version     SVN: $Id: mssql.php 2 2007-11-27 17:20:29Z mjijackson $
 * @link        http://pear.php.net/packages/PDODB
 */

/**
 * Require PDODB_Connection
 */
require_once dirname(__FILE__) . '.php';

/**
 * An MSSQL-specific database connection.
 *
 * @package     PDODB
 * @category    Database
 * @author      Frank M. Kromann <frank@kromann.info>
 * @author      Michael J. I. Jackson <mjijackson@gmail.com>
 * @todo        Test! None of this is tested yet.
 */
class PDODB_Connection_mssql extends PDODB_Connection
{

    var $id_quotes = array(
        'start' => '[',
        'end' => ']',
        'escape' => ']'
    );

    /**
     * @see     PDODB_Connection::init()
     */
    public function init()
    {
        $this->supports['sub_queries'] = true;
    }

    /**
     * @see     PDODB_Connection::errorCode()
     */
    public function errorCode(PDOException $e)
    {
        static $e_codes;

        if (empty($e_codes)) {
            $e_codes = array(
                102     => PDODB::E_SYNTAX,
                155     => PDODB::E_NOSUCHCOLUMN,
                156     => PDODB::E_SYNTAX,
                170     => PDODB::E_SYNTAX,
                207     => PDODB::E_NOSUCHCOLUMN,
                208     => PDODB::E_NOSUCHTABLE,
                245     => PDODB::E_INVALID_NUMBER,
                319     => PDODB::E_SYNTAX,
                321     => PDODB::E_NOSUCHCOLUMN,
                325     => PDODB::E_SYNTAX,
                336     => PDODB::E_SYNTAX,
                515     => PDODB::E_CONSTRAINT_NOT_NULL,
                547     => PDODB::E_CONSTRAINT,
                1018    => PDODB::E_SYNTAX,
                1035    => PDODB::E_SYNTAX,
                1913    => PDODB::E_ALREADY_EXISTS,
                2209    => PDODB::E_SYNTAX,
                2223    => PDODB::E_SYNTAX,
                2248    => PDODB::E_SYNTAX,
                2256    => PDODB::E_SYNTAX,
                2257    => PDODB::E_SYNTAX,
                2627    => PDODB::E_CONSTRAINT,
                2714    => PDODB::E_ALREADY_EXISTS,
                3607    => PDODB::E_DIVZERO,
                3701    => PDODB::E_NOSUCHTABLE,
                7630    => PDODB::E_SYNTAX,
                8134    => PDODB::E_DIVZERO,
                9303    => PDODB::E_SYNTAX,
                9317    => PDODB::E_SYNTAX,
                9318    => PDODB::E_SYNTAX,
                9331    => PDODB::E_SYNTAX,
                9332    => PDODB::E_SYNTAX,
                15253   => PDODB::E_SYNTAX,
            );
        }

        $d_code = $e->errorInfo[1];
        // sometimes errorInfo is empty...hack!
        if (is_null($d_code) && preg_match('/ \[(\d+)\] /', $e->getMessage(), $match)) {
            $d_code = $match[1];
        }

        if (isset($e_codes[$d_code])) {
            if ($d_code == 3701
                && preg_match('/Cannot drop the index/i', $e->getMessage())
            ) {
                return PDODB::E_NOT_FOUND;
            } else {
                return $e_codes[$d_code];
            }
        }

        return PDODB::E_UNKNOWN;
    }

    /**
     * @see     PDODB_Connection::modifyQuery()
     */
    protected function modifyQuery($query, $is_manip, $limit, $offset)
    {
        if ($limit > 0) {
            $fetch = $offset + $limit;
            if (!$is_manip) {
                return preg_replace('/^([\s(])*SELECT( DISTINCT)?(?!\s*TOP\s*\()/i',
                    "\\1SELECT\\2 TOP $fetch", $query);
            }
        }
        return $query;
    }

    /**
     * @see     PDODB_Connection::getDatabase()
     */
    public function getDatabase()
    {
        return $this->queryOne('SELECT db_name()');
    }

    /**
     * @see     PDODB_Connection::setDatabase()
     */
    public function setDatabase($name)
    {
        $old_db = $this->getDatabase();
        $this->exec('USE ' . $this->quoteIdentifier($name, true));
        return $old_db;
    }

    /**
     * @see     PDODB_Connection::listDatabases()
     */
    public function listDatabases()
    {
        return $this->queryCol('SELECT name FROM sys.databases');
    }

    /**
     * @see     PDODB_Connection::listTables()
     */
    public function listTables()
    {
        return $this->queryCol("SELECT name FROM sys.objects WHERE TYPE = 'u'");
    }

    /**
     * @see     PDODB_Connection::listColumns()
     */
    public function listColumns($table)
    {
        $table = $this->quoteIdentifier($table, true);
        return $this->queryCol("SELECT column_name FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '$table'");
    }

    /**
     * @see     PDODB_Connection::listFunctions()
     */
    public function listFunctions()
    {
        $query = "SELECT name
                    FROM sysobjects
                   WHERE objectproperty(id, N'IsMSShipped') = 0
                     AND (objectproperty(id, N'IsTableFunction') = 1
                      OR objectproperty(id, N'IsScalarFunction') = 1)";
        return $this->queryCol($query);
    }

    /**
     * @see     PDODB_Connection::listUsers()
     */
    public function listUsers()
    {
        return $this->queryCol('SELECT DISTINCT loginame FROM master..sysprocesses');
    }

}

?>
